package org.daochong.lang.security;

import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import sun.security.util.DerOutputStream;
import sun.security.util.DerValue;
import sun.security.util.ObjectIdentifier;
import sun.security.x509.AccessDescription;
import sun.security.x509.AuthorityInfoAccessExtension;
import sun.security.x509.AuthorityKeyIdentifierExtension;
import sun.security.x509.BasicConstraintsExtension;
import sun.security.x509.CRLDistributionPointsExtension;
import sun.security.x509.CertificateExtensions;
import sun.security.x509.DistributionPoint;
import sun.security.x509.ExtendedKeyUsageExtension;
import sun.security.x509.GeneralName;
import sun.security.x509.GeneralNameInterface;
import sun.security.x509.GeneralNames;
import sun.security.x509.KeyIdentifier;
import sun.security.x509.KeyUsageExtension;
import sun.security.x509.SubjectKeyIdentifierExtension;
import sun.security.x509.URIName;
import sun.security.x509.X500Name;

@SuppressWarnings("all")
public class CertInfoTemplateFactory {

	public static final String CAROOT = "CAROOT";
	public static final String CASUB = "CASUB";
	public static final String SERVER = "SERVER";
	public static final String USER = "USER";
	public static final String DEVICE = "DEVICE";

	private static final Map<String, CertInfoTemplate> TEMPLATES = new HashMap<String, CertInfoTemplate>();

	static {
		TEMPLATES.put(CAROOT, new CARootTemplate());
		TEMPLATES.put(CASUB, new CASubTemplate());
		TEMPLATES.put(SERVER, new CAServerTemplate());
		TEMPLATES.put(USER, new CAUserTemplate());
	}

	public static CertInfoTemplate get(String type) {
		return TEMPLATES.get(type);
	}
	
	public static AccessDescription createAccessDescription(ObjectIdentifier id,GeneralName gn){
		DerOutputStream localOut = new DerOutputStream();
		try {
			localOut.putOID(id);
			gn.encode(localOut);
			DerOutputStream out = new DerOutputStream();
			out.write((byte)48,localOut);
			byte[] data = out.toByteArray();
			localOut.close();
			out.close();
			return new AccessDescription(new DerValue(data));
		} catch (Exception e) {
			throw new RuntimeException("Create AccessDescription Fail",e);
		}
		
		
	}

}

@SuppressWarnings("all")
class CARootTemplate implements CertInfoTemplate {

	public CertificateExtensions get(CertificateResult result, CertificateRequest request) {
		try {
			CertificateExtensions ext = new CertificateExtensions();
			KeyIdentifier keyId = new KeyIdentifier(result.getPublicKey());
			AuthorityKeyIdentifierExtension authKeyId = new AuthorityKeyIdentifierExtension(keyId, null, null);
			ext.set(CertificateRequest.OID_AuthorityKeyIdentifier, authKeyId);
			ext.set(CertificateRequest.OID_SubjectKeyIdentifier,
					new SubjectKeyIdentifierExtension(keyId.getIdentifier()));
			BasicConstraintsExtension constraints = new BasicConstraintsExtension(false, -1);
			constraints.set(BasicConstraintsExtension.IS_CA, true);
			ext.set(CertificateRequest.OID_BasicConstraints, constraints);
			KeyUsageExtension keyUse = new KeyUsageExtension();
			keyUse.set(KeyUsageExtension.DIGITAL_SIGNATURE, true);
			keyUse.set(KeyUsageExtension.NON_REPUDIATION, true);
			keyUse.set(KeyUsageExtension.KEY_CERTSIGN, true);
			keyUse.set(KeyUsageExtension.CRL_SIGN, true);
			ext.set(CertificateRequest.OID_KeyUsage, keyUse);
			return ext;
		} catch (Throwable e) {
			throw new RuntimeException("create Root Extends Fail", e);
		}
	}

	public CertificateExtensions get(CertificateResult result, CertificateRequest request, Certificate issue) {
		return get(result, request);
	}
}

@SuppressWarnings("all")
class CASubTemplate implements CertInfoTemplate {

	public CertificateExtensions get(CertificateResult result, CertificateRequest request) {
		return null;
	}

	public CertificateExtensions get(CertificateResult result, CertificateRequest request, Certificate issue) {

		try {
			CertificateExtensions ext = new CertificateExtensions();
			ext.set(CertificateRequest.OID_AuthorityKeyIdentifier,
					new AuthorityKeyIdentifierExtension(new KeyIdentifier(issue.getPublicKey()), null, null));
			ext.set(CertificateRequest.OID_SubjectKeyIdentifier,
					new SubjectKeyIdentifierExtension(new KeyIdentifier(result.getPublicKey()).getIdentifier()));
			BasicConstraintsExtension constraints = new BasicConstraintsExtension(false, -1);
			constraints.set(BasicConstraintsExtension.IS_CA, true);
			ext.set(CertificateRequest.OID_BasicConstraints, constraints);
			KeyUsageExtension keyUse = new KeyUsageExtension();
			keyUse.set(KeyUsageExtension.DIGITAL_SIGNATURE, true);
			keyUse.set(KeyUsageExtension.NON_REPUDIATION, true);
			keyUse.set(KeyUsageExtension.KEY_CERTSIGN, true);
			keyUse.set(KeyUsageExtension.CRL_SIGN, true);
			ext.set(CertificateRequest.OID_KeyUsage, keyUse);
			List<String> caUrl = request.getAuthUrls();
			if (caUrl != null && caUrl.size() > 0) {
				List<AccessDescription> ais = new ArrayList<AccessDescription>();
				for (String url : caUrl) {
					GeneralNameInterface gni = new URIName(url);
					GeneralName gn = new GeneralName(gni);
					//ais.add(new AccessDescription(AccessDescription.Ad_CAISSUERS_Id, gn));
					ais.add(CertInfoTemplateFactory.createAccessDescription(AccessDescription.Ad_CAISSUERS_Id,gn));
				}
				AuthorityInfoAccessExtension aae = new AuthorityInfoAccessExtension(ais);
				ext.set(CertificateRequest.OID_AuthorityInfoAccess, aae);
			}
			caUrl = request.getCrls();
			if (caUrl != null && caUrl.size() > 0) {
				List<DistributionPoint> list = new ArrayList<DistributionPoint>();
				X500Name name = new X500Name(((X509Certificate) issue).getIssuerDN().getName());
				for (String crl : caUrl) {
					GeneralNames names = new GeneralNames();
					names.add(new GeneralName(new URIName(crl)));
					GeneralNames names1 = new GeneralNames();
					names1.add(new GeneralName(name));
					DistributionPoint point = new DistributionPoint(names1, null, names);
					list.add(point);
				}
				CRLDistributionPointsExtension points = new CRLDistributionPointsExtension(list);
				ext.set(CertificateRequest.OID_CRLDistributionPoints, points);
			}
			return ext;
		} catch (Throwable e) {
			throw new RuntimeException("create Root Extends Fail", e);
		}
	}

}

@SuppressWarnings("all")
class CAServerTemplate implements CertInfoTemplate {

	public CertificateExtensions get(CertificateResult result, CertificateRequest request) {
		return null;
	}

	public CertificateExtensions get(CertificateResult result, CertificateRequest request, Certificate issue) {

		try {
			CertificateExtensions ext = new CertificateExtensions();
			ext.set(CertificateRequest.OID_AuthorityKeyIdentifier,
					new AuthorityKeyIdentifierExtension(new KeyIdentifier(issue.getPublicKey()), null, null));
			ext.set(CertificateRequest.OID_SubjectKeyIdentifier,
					new SubjectKeyIdentifierExtension(new KeyIdentifier(result.getPublicKey()).getIdentifier()));
			KeyUsageExtension keyUse = new KeyUsageExtension();
			keyUse.set(KeyUsageExtension.DIGITAL_SIGNATURE, true);
			keyUse.set(KeyUsageExtension.KEY_ENCIPHERMENT, true);
			ext.set(CertificateRequest.OID_KeyUsage, keyUse);
			List<String> caUrl = request.getAuthUrls();
			if (caUrl != null && caUrl.size() > 0) {
				List<AccessDescription> ais = new ArrayList<AccessDescription>();
				for (String url : caUrl) {
					GeneralNameInterface gni = new URIName(url);
					GeneralName gn = new GeneralName(gni);
					//ais.add(new AccessDescription(AccessDescription.Ad_CAISSUERS_Id, gn));
					ais.add(CertInfoTemplateFactory.createAccessDescription(AccessDescription.Ad_CAISSUERS_Id,gn));
				}
				AuthorityInfoAccessExtension aae = new AuthorityInfoAccessExtension(ais);
				ext.set(CertificateRequest.OID_AuthorityInfoAccess, aae);
			}
			caUrl = request.getCrls();
			if (caUrl != null && caUrl.size() > 0) {
				List<DistributionPoint> list = new ArrayList<DistributionPoint>();
				X500Name name = new X500Name(((X509Certificate) issue).getIssuerDN().getName());
				for (String crl : caUrl) {
					GeneralNames names = new GeneralNames();
					names.add(new GeneralName(new URIName(crl)));
					GeneralNames names1 = new GeneralNames();
					names1.add(new GeneralName(name));
					DistributionPoint point = new DistributionPoint(names1, null, names);
					list.add(point);
				}
				CRLDistributionPointsExtension points = new CRLDistributionPointsExtension(list);
				ext.set(CertificateRequest.OID_CRLDistributionPoints, points);
			}
			Vector<ObjectIdentifier> list = new Vector<ObjectIdentifier>();
			list.add(new ObjectIdentifier("1.3.6.1.5.5.7.3.1"));
			ExtendedKeyUsageExtension eku = new ExtendedKeyUsageExtension(list);
			ext.set(CertificateRequest.OID_ExtendedKeyUsage, eku);
			return ext;
		} catch (Throwable e) {
			throw new RuntimeException("create Root Extends Fail", e);
		}
	}

}

@SuppressWarnings("all")
class CAUserTemplate implements CertInfoTemplate {

	public CertificateExtensions get(CertificateResult result, CertificateRequest request) {
		return null;
	}

	public CertificateExtensions get(CertificateResult result, CertificateRequest request, Certificate issue) {

		try {
			CertificateExtensions ext = new CertificateExtensions();
			ext.set(CertificateRequest.OID_AuthorityKeyIdentifier,
					new AuthorityKeyIdentifierExtension(new KeyIdentifier(issue.getPublicKey()), null, null));
			ext.set(CertificateRequest.OID_SubjectKeyIdentifier,
					new SubjectKeyIdentifierExtension(new KeyIdentifier(result.getPublicKey()).getIdentifier()));
			KeyUsageExtension keyUse = new KeyUsageExtension();
			keyUse.set(KeyUsageExtension.DIGITAL_SIGNATURE, true);
			keyUse.set(KeyUsageExtension.KEY_ENCIPHERMENT, true);
			ext.set(CertificateRequest.OID_KeyUsage, keyUse);
			List<String> caUrl = request.getAuthUrls();
			if (caUrl != null && caUrl.size() > 0) {
				List<AccessDescription> ais = new ArrayList<AccessDescription>();
				for (String url : caUrl) {
					GeneralNameInterface gni = new URIName(url);
					GeneralName gn = new GeneralName(gni);
					//ais.add(new AccessDescription(AccessDescription.Ad_CAISSUERS_Id, gn));
					ais.add(CertInfoTemplateFactory.createAccessDescription(AccessDescription.Ad_CAISSUERS_Id,gn));
				}
				AuthorityInfoAccessExtension aae = new AuthorityInfoAccessExtension(ais);
				ext.set(CertificateRequest.OID_AuthorityInfoAccess, aae);
			}
			caUrl = request.getCrls();
			if (caUrl != null && caUrl.size() > 0) {
				List<DistributionPoint> list = new ArrayList<DistributionPoint>();
				X500Name name = new X500Name(((X509Certificate) issue).getIssuerDN().getName());
				for (String crl : caUrl) {
					GeneralNames names = new GeneralNames();
					names.add(new GeneralName(new URIName(crl)));
					GeneralNames names1 = new GeneralNames();
					names1.add(new GeneralName(name));
					DistributionPoint point = new DistributionPoint(names1, null, names);
					list.add(point);
				}
				CRLDistributionPointsExtension points = new CRLDistributionPointsExtension(list);
				ext.set(CertificateRequest.OID_CRLDistributionPoints, points);
			}
			Vector<ObjectIdentifier> list = new Vector<ObjectIdentifier>();
			list.add(new ObjectIdentifier("1.3.6.1.4.1.311.10.3.4"));
			list.add(new ObjectIdentifier("1.3.6.1.5.5.7.3.4"));
			list.add(new ObjectIdentifier("1.3.6.1.5.5.7.3.2"));
			ExtendedKeyUsageExtension eku = new ExtendedKeyUsageExtension(list);
			ext.set(CertificateRequest.OID_ExtendedKeyUsage, eku);
			return ext;
		} catch (Throwable e) {
			throw new RuntimeException("create Root Extends Fail", e);
		}
	}

	
}
